﻿using System.Drawing;
using System.Drawing.Imaging;
using System.Runtime.InteropServices;
using System.Text;
using VisionKitApi;
using Image = VisionKitApi.Image;

namespace Om.Camera;

public class VkCamera : IBaseCamera
{
    private readonly string _imgSuffix = "_vk";

    public event EventHandler<bool>? ConnectionChanged;
    private bool _isConnected;
    public bool IsConnected
    {
        get => _isConnected;
        private set
        {
            if (_isConnected != value)
            {
                _isConnected = value;
                ConnectionChanged?.Invoke(this, value);
            }
        }
    }
    public event Action<byte[]>? FrameReceived;

    public string Id { get; private set; }

    public bool CanSetExposure => true;

    public async Task<List<string>> GetCameraList()
    {
        _cameraList.Clear();
        var cardNum = _cardM.VkCpEnumCard(Device_Type.DeviceTypeGigE);
        for (var i = 0; i < cardNum; i++)
        {
            // 记录所有卡信息
            var pcCardName = new byte[128];
            _cardM.VkCpGetCardName(i, ref pcCardName[0], pcCardName.Length);
            var strCardName = Encoding.Default.GetString(pcCardName, 0, pcCardName.Length);
            var card = _cardM.VkCpGetCard(strCardName);

            // 记录每个卡下所有相机信息
            var cameraNum = card.VkCpEnumCamera();
            var dic = new Dictionary<VisionKitApi.Camera, string>();
            // 如果没有相机则存一个空的结构体 用来记录这个卡
            // 遍历所有相机
            for (var j = 0; j < cameraNum; j++)
            {
                var pcCameraName = new byte[128];
                card.VkCpGetCameraName(j, ref pcCameraName[0], pcCameraName.Length);
                var strCameraName = Encoding.Default.GetString(pcCameraName, 0, pcCameraName.Length);
                var camera = card.VkCpGetCamera(strCameraName);

                var model = new CameraModel
                {
                    Camera = camera,
                    CameraName = strCameraName,
                    Card = card,
                    CardName = strCardName
                };
                _cameraList.Add(model);
            }
        }

        return _cameraList.Select(a => a.CameraName).ToList();
    }

    public async Task Connect(string cameraIpOrName)
    {
        if (_cameraList.Count == 0)
            await GetCameraList();
        if (!_cameraList.Exists(x => x.CameraName == cameraIpOrName)) throw new Exception("未找到指定相机");
        var model = _cameraList.Find(x => x.CameraName == cameraIpOrName);
        _currentCamera = model.Camera;
        if (_currentCamera.VkCpIsConnected())
            return;
        var rtn = _currentCamera.VkCpConnectCamera(DisconnectCallback, IntPtr.Zero);
        if (rtn != 0)
        {
            throw new Exception("无法连接相机");
            return;
        }

        StartGrab();
        Id = cameraIpOrName;
        IsConnected = true;
    }

    public async Task Disconnect()
    {
        if (_currentCamera != null && _currentCamera.VkCpIsConnected())
        {
            _currentCamera.VkCpStopGrab(0);
            _currentCamera.VkCpDisconnectCamera();
        }

        IsConnected = false;
    }

    public async Task Capture(string fileName)
    {
        try
        {
            using var ms = new MemoryStream(_currentBitmapBytes);
            using var bitmap = new Bitmap(ms);
            bitmap.Save(fileName, ImageFormat.Jpeg);
        }
        catch (Exception ex) { }
    }

    public async Task<bool> SetAutoExposure(bool isAutoExposure)
    {
        return false;
    }


    public async Task<bool> SetExposureValue(int val)
    {
        var res = _currentCamera.VkCpSetFeatureEnum("ExpoLVL", val.ToString());

        /*string exposureTimefeatureName = "ExposureTime";
        var res = _currentCamera.VkCpSetFeatureInt(exposureTimefeatureName, (ulong)val);*/
        return res == 0;
    }

    public async Task<int> GetExposureValue()
    {
        ulong featureValue = 0;
        if (_currentCamera.VkCpGetFeatureInt("ExposureTime", ref featureValue) == 0)
            return (int)featureValue;
        return 0;
    }

    #region MyRegion

    /// <summary>
    ///     网卡manager用于遍历网卡
    /// </summary>
    private readonly CardManager _cardM = new();

    private readonly List<CameraModel> _cameraList = new();

    private VisionKitApi.Camera _currentCamera;
    private byte[] _currentBitmapBytes;

    /// <summary>
    ///     是否正在采集图像
    /// </summary>
    private bool _isGrabbing;


    private void StartGrab()
    {
        if (_currentCamera == null || !_currentCamera.VkCpIsConnected())
            throw new Exception("请先连接相机");

        var res = _currentCamera.VkCpCallBackRegister(0, ImageCallback);
        res = _currentCamera.VkCpStartGrab(0, 50000, IntPtr.Zero);
    }

    private void ImageCallback(Image image, IntPtr context)
    {
        var imageInfo = new IMAGEINFO();
        image.VkCpGetImageInfo(ref imageInfo);

        if (imageInfo.format == Convert.ToUInt32(PIXEL_FORMAT.PIXEL_FORMAT_RGB8))
        {
            var img = image.VkCpGetImageBuff();
            var width = Convert.ToInt32(imageInfo.width);
            var height = Convert.ToInt32(imageInfo.height);
            var length = width * height * 3;
            var data = new byte[length];
            Marshal.Copy(img, data, 0, data.Length);
            var rgbvalues = new byte[data.Length];

            //对每一个像素的颜色进行转化
            for (var i = 0; i < rgbvalues.Length; i += 3)
            {
                rgbvalues[i] = data[i + 2];
                rgbvalues[i + 1] = data[i + 1];
                rgbvalues[i + 2] = data[i];
            }

            var bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
            var bmpdata = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly,
                PixelFormat.Format24bppRgb);
            Marshal.Copy(rgbvalues, 0, bmpdata.Scan0, length);
            bmp.UnlockBits(bmpdata);

            var bytes = BitmapToBytes(bmp);
            _currentBitmapBytes = bytes;
            FrameReceived?.Invoke(bytes);
        }
        else if (imageInfo.format == Convert.ToUInt32(PIXEL_FORMAT.PIXEL_FORMAT_MONO8))
        {
            var img = image.VkCpGetImageBuff();
            var width = Convert.ToInt32(imageInfo.width);
            var height = Convert.ToInt32(imageInfo.height);
            var length = width * height;
            var data = new byte[length];
            Marshal.Copy(img, data, 0, data.Length);
            var bmp = new Bitmap(width, height, PixelFormat.Format8bppIndexed);
            var bmpdata = bmp.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.WriteOnly,
                PixelFormat.Format8bppIndexed);
            Marshal.Copy(data, 0, bmpdata.Scan0, length);
            //下面的代码是为了修改生成位图的索引表，从伪彩修改为灰度
            ColorPalette tempPalette;
            using (var tempBmp = new Bitmap(1, 1, PixelFormat.Format8bppIndexed))
            {
                tempPalette = tempBmp.Palette;
            }

            for (var i = 0; i < 256; i++) tempPalette.Entries[i] = Color.FromArgb(i, i, i);
            bmp.Palette = tempPalette;
            bmp.UnlockBits(bmpdata);

            var bytes = BitmapToBytes(bmp);
            _currentBitmapBytes = bytes;
            FrameReceived?.Invoke(bytes);
        }

        image.VkCpImageRelease();
    }

    private byte[] BitmapToBytes(Bitmap bitmap)
    {
        using var ms = new MemoryStream();
        bitmap.Save(ms, ImageFormat.Jpeg);
        return ms.ToArray();
    }

    public void Stop()
    {
        if (_currentCamera != null && _currentCamera.VkCpIsConnected()) _currentCamera.VkCpStopGrab(0);
    }


    private void DisconnectCallback(uint ev, IntPtr context)
    {
    }


    private struct CameraModel
    {
        public VisionKitApi.Camera Camera;
        public string CameraName;
        public Card Card;
        public string CardName;
    }

    #endregion
}